<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**************************************************************************
 *
 *   Copyright 2010 American Public Media Group
 *
 *   This file is part of AIR2.
 *
 *   AIR2 is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   AIR2 is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with AIR2.  If not, see <http://www.gnu.org/licenses/>.
 *
 *************************************************************************/

/**
 * AirTag Library
 *
 * Contains methods to fetch, add, and remove tags to any resource (doctrine
 * model) in AIR2.  Used in conjunction with AIR2_CRUD_Controller.
 *
 * @author rcavis
 * @package default
 */
class AirTag {

    /**
     * Fetches tags for a record
     *
     * @param Doctrine_Record $rec
     * @param array   $opt (optional) paging/query options to add (limit, etc)
     * @return array the result data
     */
    public function fetch(&$rec, $opt=array()) {
        $q = $this->create_tag_query($rec);

        // apply options
        if (isset($opt['limit']) && $opt['limit']) {
            $q->limit($opt['limit']);
        }
        if (isset($opt['start']) && $opt['start']) {
            $q->offset($opt['start']);
        }
        if (isset($opt['sort']) && $opt['sort']) {
            $dir = $opt['dir'] || 'ASC';
            $q->orderBy($opt['sort']." $dir");
        }

        return $this->exec_tag_query($q, true, true);
    }


    /**
     * Add a tag to a record
     *
     * @param Doctrine_Record $rec
     * @param array   $add_data indicates which tag to add ('tm_id' or 'tm_name')
     * @return array the added tag
     */
    public function add(&$rec, $add_data) {
        // must have set either tm_id or tm_name
        if (!isset($add_data['tm_id']) && !isset($add_data['tm_name'])) {
            throw new Exception("Error: A valid tag was not specified");
        }

        // create new tag_master, if necessary
        $tm_id_value = isset($add_data['tm_id']) ? $add_data['tm_id'] : null;
        if (!$tm_id_value) {
            // check for duplicates (same name)
            $dup = Doctrine::getTable('TagMaster')->findOneBy('tm_name', $add_data['tm_name']);
            if ($dup) {
                $tm_id_value = $dup->tm_id;
            }
            else {
                // create new tag_master record
                $tm = new TagMaster();
                $tm->tm_type = 'J'; // Journalistic (right now, Users can't create IPTC-type tag_masters)
                $tm->tm_name = $add_data['tm_name'];
                $tm->save();
                $tm_id_value = $tm->tm_id;
            }
        }

        // screen for duplicates
        $q = $this->create_tag_query($rec);
        $q->addWhere('tm_id = ?', $tm_id_value);
        $dup = $q->fetchOne();
        if ($dup) {
            throw new Exception('Tag already exists!');
        }

        // attempt to add tag_master to this record's tags
        $rec->Tags[]->tag_tm_id = $tm_id_value;
        $rec->save();

        // success! Fetch tag to get all related fields
        return $this->exec_tag_query($q, false, false);
    }


    /**
     * Removes a tag from a record
     *
     * @param Doctrine_Record $rec
     * @param string|int $tag_uuid the primary key ID of the tag to remove
     * @return boolean whether or not a tag was removed
     */
    public function remove(&$rec, $tag_uuid) {
        // find the tag record
        $q = $this->create_tag_query($rec);
        $q->addWhere('tm_id = ?', $tag_uuid);
        $q->addSelect('t.*');
        $tag_master = $q->fetchOne();
        if (!$tag_master) return false; //ignore this removal
        $tag = $tag_master->Tag[0];

        // remove tag from this resource
        $delete_tag_master = false; // remove unused tags
        if ($tag_master->usage == 1 && $tag_master->tm_type != 'I') {
            $delete_tag_master = true;
        }

        $conn = AIR2_DBManager::get_master_connection();
        $conn->beginTransaction();
        $tag->delete();
        if ($delete_tag_master) $tag_master->delete();
        $conn->commit();
        return true;
    }


    /**
     * Creates a doctrine query to fetch tags for a record
     *
     * @param Doctrine_Record $rec
     * @return AIR2_Query
     */
    public function create_tag_query(&$rec) {
        $rel = $rec->getTable()->getRelation('Tags');
        $xid_field = $rel->getLocalFieldName();
        $xid = $rec[$xid_field];

        $opt = $rel->getTable()->getOptions();
        $ref_type = $opt['inheritanceMap']['tag_ref_type'];

        $usage = 'select COUNT(*) from tag where tag_tm_id = a.tm_id';
        $q = AIR2_Query::create()
        ->select("a.*, m.*, ($usage) as usage, t.tag_cre_dtim as added_dtim")
        ->from("TagMaster a, a.IptcMaster m, a.Tag t")
        ->where('t.tag_xid = ?', $xid)
        ->andWhere('t.tag_ref_type = ?', $ref_type);
        return $q;
    }


    /**
     * Executes a tag query
     *
     * @param AIR2_Query $q
     * @param boolean $meta add metadata to results
     * @param boolean $list return results as list
     * @return array the resulting data
     */
    public function exec_tag_query(&$q, $meta, $list) {
        // execute the query
        $params = array(
            'add_meta'    => $meta,
            'return_list' => $list,
            'blacklist'   => array(),
            'whitelist'   => array(),
            'extra'       => array(
                array('name' => 'usage', 'type' => 'int'),
                array('name' => 'added_dtim', 'type' => 'date', 'dateFormat' => AIR2_DTIM_FORMAT),
            ),
        );
        $CI =& get_instance();
        return $CI->airquery->execute_query($q, $params);
    }


}
